/**
 * @类名称:Pay.java
 * @date:2017年6月5日上午11:55:46
 * @author:zhengzihang
 * @版权:微辰金服有限公司 Copyright (c) 2017
 */
package cn.vcjf.weapp.api.payment.qfwxpay.service;

import cn.vcjf.weapp.api.payment.qfwxpay.model.VcQfPayRes;
import cn.vcjf.weapp.common.util.httpUtils.HttpClientUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 钱方支付 退款接口
 *
 * @author zhengzihang
 * @apiNote :QfPayApi.java
 * @版权:微辰金服有限公司 Copyright (c) 2018
 */
public abstract class AbstractQfRefundService<T> {

    public static String CODE = "E85AB5AF2943441D80FB838B6C228640";
    public static String KEY = "8A920BE9718C414982EB5950216429C0";

    public static String REFUND_URL = "https://openapi-test.qfpay.com/trade/v1/refund";

    private static Logger logger = LogManager.getLogger(AbstractQfRefundService.class);

    /**
     * @param requestMap :{money,orderNo,merchId} 封装所有request请求参数requestMap
     * @apiNote:POST入口
     * @author:zhengzihang
     * @date:2017年6月5日 下午1:26:37
     */
    public VcQfPayRes doRefund(Map<String, String> requestMap) {
        VcQfPayRes res = new VcQfPayRes();
        try {
            logger.info("QF商户发起请求退款开始");
            res = this.invokeRefund(requestMap);
            logger.info("退款给下游返回json，{}", JSON.toJSONString(res));
            return res;
        } catch (IllegalArgumentException e) {
            logger.error("QF退款请求发起失败", e);
            res.setCode("10001");
            res.setMsg("退款请求发起失败:" + e.getMessage());
            res.setErrMsg("退款请求发起失败" + e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("QF请求退款异常", e);
            res.setCode("10004");
            res.setMsg("请求退款异常");
            res.setErrMsg("请求退款异常");
        }
        return res;
    }

    /**
     * @apiNote:退款操作
     * @author:zhengzihang
     * @date:2017年6月5日 下午2:29:28
     */
    @SuppressWarnings("all")
    public VcQfPayRes invokeRefund(Map<String, String> requestMap) throws IllegalArgumentException, ServletException, IOException {
        String money = requestMap.get("money");
        String orderNo = requestMap.get("orderNo");
        String merchId = requestMap.get("merchId");
        //校验订单信息
        List<T> orderList = findTOrderByNo(orderNo);

        if (orderList == null || orderList.isEmpty()) {
            throw new IllegalArgumentException("订单信息不存在");
        }
        T order = orderList.get(0);
        if (order == null ) {
            throw new IllegalArgumentException("订单信息不存在");
        }
        if (getOrderSuccessStatus(order) != getOrderStatus(order)) {
            throw new IllegalArgumentException("该订单暂时不能发起退款");
        }
        if ("0".equals(money)) {
            money = getTraAmount(order).toString();
        }
        //退款金额大于订单交易金额
        if (new BigDecimal(money).compareTo(getTraAmount(order)) != 0) {
            throw new IllegalArgumentException("退款金额不等于于实际订单金额");
        }

        return excuteRefund(order, merchId);
    }

    protected abstract BigDecimal getTraAmount(T order);

    protected abstract long getOrderSuccessStatus(T order);

    protected abstract long getOrderStatus(T order);

    protected abstract List<T> findTOrderByNo(String orderNo);

    protected abstract String getPayOrderNo(T order);

    protected abstract String getOrderNo(T order);

    protected abstract int doRefundSuccess(T order, JSONObject ressultJson);

    protected abstract int doRefundFailed(T order, JSONObject ressultJson);

    public VcQfPayRes excuteRefund(T order, String mchId) throws IOException, ServletException {
        VcQfPayRes res;
        SortedMap<String, String> bodyMap = getBodyMap(order, mchId);
        Map<String, String> headMap = getHeaderMap(bodyMap);
        String result = HttpClientUtils.httpSendPostFrom(REFUND_URL, bodyMap, headMap);
        logger.info("钱方退款:返回信息：{}" + result);
        JSONObject ressultJson = JSONObject.parseObject(result);
        if (ressultJson == null) {
            res = VcQfPayRes.failedPayResp("退款请求发起失败");
            return res;
        }
        if ("0000".equals(ressultJson.get("respcd"))) {
            doRefundSuccess(order,ressultJson);
            res = VcQfPayRes.successPayRes("退款发起成功");
        } else {
            doRefundFailed(order,ressultJson);
            res = VcQfPayRes.failedPayResp(ressultJson.getString("resperr"));
        }
        return res;
    }

    /**
     * @apiNote:构建钱方退款参数
     * @author:zhengzihang
     * @date:2018年1月31日 上午10:13:35
     */
    private SortedMap<String, String> getBodyMap(T order, String mchId) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SortedMap<String, String> sortedMap = new TreeMap<>();
        sortedMap.put("syssn", getPayOrderNo(order));
        sortedMap.put("out_trade_no", getOrderNo(order) + "TK");
        sortedMap.put("txamt", getTraAmount(order).toString());
        sortedMap.put("txdtm", sdf.format(new Date()));
        sortedMap.put("mchid", mchId);
        SortedMap<String, String> params = HttpClientUtils.paraFilter(sortedMap);
        String sign = HttpClientUtils.getSign(params, KEY);
        sortedMap.put("sign", sign);
        logger.info("钱方退款:请求参数信息：{}" , sortedMap);
        return sortedMap;
    }

    /**
     *
     * @param sortedMap
     * @return
     */
    private Map<String, String> getHeaderMap(SortedMap<String, String> sortedMap) {
        Map<String, String> headerMap = new HashMap<>();
        headerMap.put("X-QF-SIGN", sortedMap.get("sign"));
        headerMap.put("X-QF-APPCODE", CODE);
        sortedMap.remove("sign");
        logger.info("钱方退款:请求头信息：{}" , sortedMap);
        return headerMap;
    }

    /**
     * @apiNote:获取请求参数
     * @author:zhengzihang
     * @date:2017年7月3日 下午7:54:35
     */
    public Map<String, String> geRequestMap(HttpServletRequest request) throws ServletException {
        String customerId = request.getParameter("customerId");
        String orderNo = request.getParameter("orderNo");
        String money = request.getParameter("money");
        String sign = request.getParameter("sign");
        String nonceStr = request.getParameter("nonceStr");

        SortedMap<String, String> requestMap = new TreeMap<String, String>();
        requestMap.put("customerId", customerId);
        requestMap.put("orderNo", orderNo);
        requestMap.put("money", money);
        requestMap.put("nonceStr", nonceStr);

        return requestMap;
    }

    /**
     * @apiNote:setHttpServletContent
     * @author:zhengzihang
     * @date:2017年6月5日 下午7:59:02
     */
    public void setHttpServletContent(HttpServletRequest request, HttpServletResponse response) throws IOException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json;charset=utf-8");
    }
}
